package com.kaibes.module.file.local;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.kaibes.core.base.option.BooleanOptions;
import com.kaibes.core.base.util.FileUtils;
import com.kaibes.core.base.util.MathUtils;
import com.kaibes.core.base.util.Md5Utils;
import com.kaibes.module.file.local.db.FileInfo;
import com.kaibes.module.file.local.db.FileInfoService;
import com.kaibes.module.file.local.db.FileMark;
import com.kaibes.module.file.local.db.FileMarkService;
import com.kaibes.module.file.local.to.UploadTO;
import com.kaibes.web.response.ResponseFactory;
import com.kaibes.web.util.WebUtils;

@Service
public class FileLocalService {

    @Autowired
    private FileInfoService fileInfoService;
    @Autowired
    private FileMarkService fileMarkService;
    @Autowired
    private FileConfig fileConfig;
    @Autowired
    private FileTransaction fileTransaction;

    public File[] unZip(String uuid) {
        FileMark fileMark = fileMarkService.getByUuid(uuid);
        return unZip(fileMark);
    }
    
    public File[] unZip(FileMark fileMark) {
        if (fileMark != null) {
            FileInfo fileInfo = fileInfoService.getById(fileMark.getFileInfoId());
            return unZip(fileInfo);
        }
        return null;
    }

    public File[] unZip(FileInfo fileInfo) {
        if (fileInfo == null) {
            return null;
        }
        File fint = new File(fileInfo.getPath());
        String path = fint.getAbsolutePath();
        if (fint.exists() && FileUtils.isArchiveFile(path)) {
        	String out = fileConfig.getCache();
        	FileUtils.unCompress(path, out, Charset.forName("GBK"));
            String filename = new File(path).getName();
            filename = filename.substring(0, filename.lastIndexOf("."));
            out = out + filename;
            File fout = new File(out);
            File[] files = fout.listFiles();
            while (files.length == 1 && files[0].isDirectory()) {
                files = files[0].listFiles();
            }
            return files;
        }
        return null;
    }

    public void getByFileInfo4list(HttpServletRequest request, HttpServletResponse response, FileInfo fileInfo, String name) {
        File[] files = unZip(fileInfo);
        if (files != null && files.length > 0) {
            File file = null;
            if (MathUtils.isInteger(name)) {
                files = FileUtils.sort(files);
                int page = Integer.parseInt(name);
                if (page > 0 && files.length >= page) {
                    file = files[page - 1];
                }
            } else {
                file = new File(files[0].getParentFile().getAbsolutePath() + "/" + name);
            }
            if (file != null && file.exists()) {
            	BooleanOptions.ifTrue(WebUtils.downFile(file, fileInfo.getName()), 
            			()->fileInfoService.addCount(fileInfo.getId()));
            }
        }
        try {
            response.getOutputStream().flush();
            response.getOutputStream().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void getByFileInfo(HttpServletRequest request, HttpServletResponse response, FileInfo fileInfo) {
        if (fileInfo == null) {
            return;
        }
        File file = new File(fileInfo.getPath());
        BooleanOptions.ifTrue(WebUtils.downFile(file, fileInfo.getName()), 
        		()->fileInfoService.addCount(fileInfo.getId()));
    }

    public ResponseEntity<UploadTO> upload(Integer userId, MultipartFile multipartFile, String checkMd5) {
        UploadTO uploadTO = new UploadTO();
        if (multipartFile == null || multipartFile.isEmpty()) {
            uploadTO.setMsg("上传失败，文件异常");
            return ResponseFactory.postFailure(uploadTO);
        }

        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String contetType = multipartFile.getContentType();
        String filename = multipartFile.getOriginalFilename();
        String suffix = FileUtils.getSuffix4Name(multipartFile.getOriginalFilename());
        String path = fileConfig.getPath(uuid + suffix);
        uploadTO.setUuid(uuid);

        try {
            Files.copy(multipartFile.getInputStream(), Paths.get(path), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            uploadTO.setMsg("上传失败，保存文件出错");
            return ResponseFactory.postFailure(uploadTO);
        }

        File cache = new File(path);
        String md5 = Md5Utils.getMD5Code(cache).toUpperCase();
        if (checkMd5 != null && !md5.equals(checkMd5.toUpperCase())) {
            cache.delete();
            uploadTO.setMsg("上传失败，MD5验证不通过");
            return ResponseFactory.postFailure(uploadTO);
        }

        FileInfo fileInfo = fileInfoService.getByMD5(md5);
        boolean flag = true;
        if (fileInfo == null) {
            fileInfo = new FileInfo();
            fileInfo.setMd5(md5);
            fileInfo.setName(filename);
            fileInfo.setSuffix(suffix);
            fileInfo.setType(contetType);
            fileInfo.setSize(cache.length());
            fileInfo.setPath(path.replaceAll("\\\\", "/"));
            fileInfo.setAccessCount(0);
            fileInfo.setCreateTime(LocalDateTime.now());
            fileInfo.setAccessTime(fileInfo.getCreateTime());
            uploadTO.setData(fileInfo);
            flag = fileTransaction.saveFile(fileInfo, uuid, userId);
        } else {
            uploadTO.setData(fileInfo);

            FileMark fileMark = new FileMark();
            fileMark.setFileInfoId(fileInfo.getId());
            fileMark.setUuid(uuid);
            fileMark.setName(fileInfo.getName());
            fileMark.setUserId(userId);
            fileMark.setSuffix(fileInfo.getSuffix());
            fileMark.setType(fileInfo.getType());
            flag = fileMarkService.save(fileMark) != null;
            cache.delete();
        }

        if (flag) {
            uploadTO.setMsg("上传文件成功");
            uploadTO.setUuid(uuid);
            return ResponseFactory.postSuccess(uploadTO);
        } else {
            uploadTO.setMsg("上传失败，未知原因");
            return ResponseFactory.postFailure(uploadTO);
        }
    }

    public HashMap<String, Integer> list(String uuid) {
    	File[] files = unZip(uuid);
        HashMap<String, Integer> map = new HashMap<>(1);
        if (files != null) {
        	map.put("length", files.length);
        } else {
        	map.put("length", 0);
        }
        return map;
    }
    
    public byte[] getContent(String uuid) {
    	FileMark mark = fileMarkService.getByUuid(uuid);
    	FileInfo info = fileInfoService.getById(mark.getFileInfoId());
    	String path = info.getPath();
    	return FileUtils.getBytes(path);
    }
    
    public String getTextByMd5(String md5) {
    	FileInfo info = fileInfoService.getByMD5(md5);
    	String path = info.getPath();
    	return FileUtils.getText(path);
    }
    
    public String getTextByUuid(String uuid) {
    	FileMark mark = fileMarkService.getByUuid(uuid);
    	FileInfo info = fileInfoService.getById(mark.getFileInfoId());
    	String path = info.getPath();
    	return FileUtils.getText(path);
    }
    
}
